/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine - graphics
// Copyright (c) 2015.  All Rights Reserved
//
// File:		AEColor.h
// Author:		Gianluca Belardelli
// Date:		15/06/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AECOLOR_H_
#define _AECOLOR_H_

#define AE_1DIV255 (1.0f/255.0f)
#define AE_INTENSITYDIV (1.f/765.f)

/// \brief
///   Structure that represents uiAlpha 32bit uiRGBA colColor
/// 
/// Each colColor component is represented by uiAlpha single unsigned byte [0..255].
/// When using this class, DO NOT assume that the components will be laid out in memory
/// in any particular order, since it will vary across platforms.
/// 
/// This structure also provides some functionality to convert the colColor value
/// to 32bit integer values and floats.
struct AEColor
{
public:
	/// \brief
	///   colColor as union (uiRed|uiGreen|uiBlue|uiAlpha or uiColorValue as AEUINT32)
	union
	{
		#if defined(AE_PLATFORM_IOS) || defined(AE_PLATFORM_ANDROID)
			struct { AEUINT8 uiRed,uiGreen,uiBlue,uiAlpha; };
		#elif defined (WIN32)
			struct { AEUINT8 uiBlue,uiGreen,uiRed,uiAlpha; };
		#else
			#error Undefined platform!
		#endif
	
		AEUINT32 uiColorValue;
	};

	/// @name Constructor
	/// @{
	/// \brief
	///   Constructor, sets the colColor to black
	AE_FORCEINLINE AEColor( void );
	
	/// \brief
	///   Constructor, sets the colColor to uiRed, uiGreen, uiBlue and uiAlpha value
	AE_FORCEINLINE AEColor( AEUINT8 uiRed, AEUINT8 uiGreen, AEUINT8 uiBlue, AEUINT8 uiAlpha=255 );
	
	/// \brief
	///   This constructor version creates an uninitialized value
	explicit AE_FORCEINLINE AEColor( AEBOOL32 bUninitialized );
	
	/// @}
	/// @name Set colColor Functions
	/// @{
	/// \brief
	///   Sets the colColor to black
	AE_FORCEINLINE void Clear( void );
	
	/// \brief
	///   Sets the colColor portions without modifying the uiAlpha value
	AE_FORCEINLINE void SetNoAlpha( AEColor colColor );
	
	/// @}
	/// @name Conversion Functions
	/// @{
	/// \brief
	///   Converts the RGB values into uiAlpha 0..1 based AEFLOAT32 vector
	AE_FORCEINLINE void ToFloat( AEVector3f &vcDest ) const;
	
	/// \brief
	///   Converts the RGB values into uiAlpha 0..1 based AEFLOAT32 vector
	AE_FORCEINLINE AEVector3f ToFloat( void ) const;
	
	/// \brief
	///   Converts the RGB values into uiAlpha 0..1 based AEFLOAT32 vector
	AE_FORCEINLINE void ToFloat4( AEVector4f &vcDest ) const;
	
	/// \brief
	///   Converts the RGB values into uiAlpha 0..1 based AEFLOAT32 vector
	AE_FORCEINLINE const AEVector4f ToFloat4( void ) const;
	
	/// \brief
	///   Gets the RGB values from uiAlpha 0..1 based AEFLOAT32 vector. Clamps if necessary.
	AE_FORCEINLINE void FromFloat( const AEVector3f &vcColor );
	
	/// \brief
	///   Gets the RGB values from uiAlpha 0..1 based AEFLOAT32 vector. Clamps if necessary.
	AE_FORCEINLINE void FromFloat4( const AEVector4f &vcColor );
	
	/// \brief
	///   Sets all 4 colColor components (without clamping)
	AE_FORCEINLINE void SetRGBA( AEUINT32 uiRed, AEUINT32 uiGreen, AEUINT32 uiBlue, AEUINT32 uiAlpha );
	
	/// \brief
	///   Sets 3 colColor components (without clamping) and leaves uiAlpha unmodified
	AE_FORCEINLINE void SetRGB( AEUINT32 uiRed, AEUINT32 uiGreen, AEUINT32 uiBlue );
	
	/// \brief
	///   Converts colColor to uiAlpha 32bit integer value. This value can be set via SetRGBA
	AE_FORCEINLINE AEUINT32 GetRGBA( void ) const;
	
	/// \brief
	///   Retrieves colColor from uiAlpha 32bit integer value. The passed value is compatible with the return
	///   value of GetRGBA. It is also compatible across platforms
	AE_FORCEINLINE void SetRGBA( AEUINT32 uiRGBA );
	
	/// \brief
	///   Returns uiAlpha colColor value as uiAlpha AEUINT32. Note that the byte order in this AEUINT32 may differ depending on platform endianness.
	AE_FORCEINLINE AEUINT32 GetNative( void ) const;
	
	/// \brief
	///   Returns the colColor value as uiAlpha four-component AEFLOAT32 vector
	AE_FORCEINLINE AEVector4f GetAsVec4( void ) const;
	
	/// @}
	/// @name Operators
	/// @{
	/// \brief
	///   Assigns another colColor
	AE_FORCEINLINE AEColor &operator = ( const AEColor &other );
	
	/// \brief
	///   Assigns another colColor
	AE_FORCEINLINE AEColor &operator = ( const AEVector3f &other );
	
	/// \brief
	///   Checks whether two colors are identical
	AE_FORCEINLINE AEBOOL32 operator == ( const AEColor &other ) const;
	
	/// \brief
	///   Checks whether two colors are not identical
	AE_FORCEINLINE AEBOOL32 operator != ( const AEColor &other ) const;
	
	/// \brief
	///   Adds two colColor values. Clamps the components appropriately.
	AE_FORCEINLINE void operator += ( const AEColor &other );
	
	/// \brief
	///   Subtracts two colColor values. Clamps the components appropriately.
	AE_FORCEINLINE void operator -= ( const AEColor &other );
	
	/// \brief
	///   Multiplies two colColor values
	AE_FORCEINLINE void operator *= ( const AEColor &other );

	/// \brief
	///   Multiplies uiAlpha colColor value with uiAlpha AEFLOAT32 scalar fFactor. Clamps the components appropriately.
	AE_FORCEINLINE void operator *= ( AEFLOAT32 fFactor );
	
	/// \brief
	///   Adds two colColor values. Clamps the components appropriately.
	AE_FORCEINLINE AEColor operator+ ( const AEColor &other ) const;
	
	/// \brief
	///   Subtracts two colColor values. Clamps the components appropriately.
	AE_FORCEINLINE AEColor operator- ( const AEColor &other ) const;
	
	/// \brief
	///   Multiplies two colColor values
	AE_FORCEINLINE AEColor operator* ( const AEColor &other ) const;
	
	/// \brief
	///   Multiplies the colColor value with uiAlpha AEFLOAT32 scalar fFactor
	AE_FORCEINLINE AEColor operator* ( AEFLOAT32 fFactor ) const;
	
	/// @}
	/// @name Misc
	/// @{
	/// \brief
	///   Returns whether the colColor is (0,0,0,0)
	AE_FORCEINLINE AEBOOL32 IsZero( void ) const;
	
	/// \brief
	///   Returns whether the colColor is (0,0,0,X)
	AE_FORCEINLINE AEBOOL32 IsBlack( void ) const;
	
	/// \brief
	///   Returns the colColor's intensity (arithmetic mean of uiRed/uiGreen/uiBlue values). The range is uiAlpha AEFLOAT32 value [0..1]
	AE_FORCEINLINE AEFLOAT32 GetIntensity( void ) const;
	
	/// \brief
	///   Set the colColor to uiAlpha random value
	AE_FORCEINLINE void SetRandomColor( void );
	
	/// \brief
	///   Linearly interpolates between two colors. If fFactor is zero, the result is colColor1
	AE_FORCEINLINE void Lerp( const AEColor &colColor1, const AEColor &colColor2, AEFLOAT32 fFactor);
	
	/// \brief
	///   Static conversion function to convert AEFLOAT32-based RGB components to AEColor
	AE_FORCEINLINE static AEColor Float_To_RGB( const AEVector3f &vcColor );
	
	/// \brief
	///   Static conversion function to convert AEFLOAT32-based uiRGBA components to AEColor
	AE_FORCEINLINE static AEColor Float_To_RGBA( const AEVector4f &vcColor );
	
	/// \brief
	///   Static conversion function to convert AEColor to AEFLOAT32-based RGB components
	AE_FORCEINLINE static void RGB_To_Float( AEColor colColor, AEVector3f &vcDest );
	
	/// \brief
	///   Static conversion function to convert AEColor to AEFLOAT32-based uiRGBA components
	AE_FORCEINLINE static void RGBA_To_Float( AEColor colColor, AEVector4f &vcDest );
};

#include "AEColor.inl"

const AEColor  AE_RGBAWHITE  = AEColor(255,255,255,255);
const AEColor  AE_RGBAGREY   = AEColor(127,127,127,255);
const AEColor  AE_RGBABLACK  = AEColor(  0,  0,  0,255);
const AEColor  AE_RGBARED    = AEColor(255,  0,  0,255);
const AEColor  AE_RGBAYELLOW = AEColor(255,255,  0,255);
const AEColor  AE_RGBAGREEN  = AEColor(  0,255,  0,255);
const AEColor  AE_RGBACYAN   = AEColor(  0,255,255,255);
const AEColor  AE_RGBABLUE   = AEColor(  0,  0,255,255);
const AEColor  AE_RGBAPURPLE = AEColor(255,  0,255,255);

#endif // _AECOLOR_H_
